import L from 'leaflet';

// 这里原先是 export * from '../components/SelectInteraction';
// 现在已将 SelectInteraction 逻辑全部内置于本文件，无需再导出或引用原 components 目录。

/**
 * 地图要素选择交互工具类，支持单选高亮 marker/polyline/polygon
 */
export class SelectInteraction {
  private map: L.Map;
  private selectedLayer: L.Layer | null = null;
  private originalStyle: any = null;
  private enabled = false;
  private layers: L.Layer[] = [];
  private selectMode: 'single' | 'rectangle' | 'polygon' = 'single';
  private _tempRect: L.Rectangle | null = null;
  private _lastSelected: L.Layer[] = [];
  private _onDomContextMenu: any;
  private _rectangleMouseMoveHandler: any;
  private _rectangleMouseDownHandler: any;
  private _rectangleContextMenuHandler: any;

  constructor(map: L.Map) {
    this.map = map;
  }

  /**
   * 启用选择模式，对传入的图层数组绑定点击事件
   */
  public enableSelect(layers: L.Layer[], onSelect?: (layer: L.Layer | L.Layer[]) => void) {
    this.disableSelect(); // 先清理
    this.layers = layers;
    this.enabled = true;
    this.selectedLayer = null;      // 新增，重置上一次选中
    this._lastSelected = [];        // 新增，重置上一次多选
    this.originalStyle = null;      // 新增，重置上一次样式
    this.map.getContainer().style.cursor = 'pointer';
    if (this.selectMode === 'single') {
      layers.forEach(layer => {
        layer.on('click', this.handleLayerClick(onSelect));
        layer.on('mouseover', this.handleMouseOver);
        layer.on('mouseout', this.handleMouseOut);
      });
    } else if (this.selectMode === 'rectangle') {
      this.enableRectangleSelect(onSelect);
    } else if (this.selectMode === 'polygon') {
      this.enablePolygonSelect(onSelect);
    }
  }

  /**
   * 关闭选择模式，解绑事件并恢复样式
   */
  public disableSelect() {
    if (!this.enabled) return;
    this.enabled = false;
    this.map.getContainer().style.cursor = '';
    // 恢复所有事件和样式
    this.layers.forEach(layer => {
      layer.off('click');
      layer.off('mouseover');
      layer.off('mouseout');
      // 退出时恢复为初始样式（不高亮）
      if ((layer as any)._originalStyle) {
        (layer as any).setStyle?.((layer as any)._originalStyle);
      }
      // 兼容 L.GeoJSON 类型（FeatureGroup 或 LayerGroup）
      if ((layer as any).eachLayer) {
        (layer as any).eachLayer((subLayer: any) => {
          if (subLayer && subLayer.setStyle && subLayer._originalStyle) {
            subLayer.setStyle(subLayer._originalStyle);
          }
        });
      }
    });
    if (this.selectedLayer && this.originalStyle) {
      (this.selectedLayer as any).setStyle?.(this.originalStyle);
      // 兼容 L.GeoJSON 类型
      if ((this.selectedLayer as any).eachLayer) {
        (this.selectedLayer as any).eachLayer((subLayer: any) => {
          if (subLayer && subLayer.setStyle && subLayer._originalStyle) {
            subLayer.setStyle(subLayer._originalStyle);
          }
        });
      }
    }
    this.selectedLayer = null;
    this.originalStyle = null;
    this.layers = [];
    // 彻底移除临时矩形和相关事件
    if (this._tempRect) {
      try {
        if (this.map.hasLayer(this._tempRect)) {
          this.map.removeLayer(this._tempRect);
        }
      } catch (err) { /* 忽略异常 */ }
      this._tempRect = null;
    }
    // 解绑所有 map 上的 mousemove、mousedown、contextmenu 事件（只用带回调的解绑）
    if (this._rectangleMouseMoveHandler) {
      this.map.off('mousemove', this._rectangleMouseMoveHandler);
      this._rectangleMouseMoveHandler = null;
    }
    if (this._rectangleMouseDownHandler) {
      this.map.off('mousedown', this._rectangleMouseDownHandler);
      this._rectangleMouseDownHandler = null;
    }
    if (this._rectangleContextMenuHandler) {
      this.map.getContainer().removeEventListener('contextmenu', this._rectangleContextMenuHandler);
      this._rectangleContextMenuHandler = null;
    }
    if (this._onDomContextMenu) {
      this.map.getContainer().removeEventListener('contextmenu', this._onDomContextMenu as any);
      this._onDomContextMenu = null;
    }
  }

  /**
   * 获取当前选中图层
   */
  public getSelectedLayer() {
    return this.selectedLayer;
  }

  public setSelectMode(mode: 'single' | 'rectangle' | 'polygon') {
    this.selectMode = mode;
  }

  // 单击选中事件，样式与矩形/多边形选中保持一致，并处理重置逻辑
  private handleLayerClick = (onSelect?: (layer: L.Layer) => void) => (e: any) => {
    const layer = e.target as L.Layer;
    // ——参考矩形框选方式，重置所有高亮——
    this.layers.forEach(l => {
      if ((l as any)._originalStyle) {
        (l as any).setStyle?.((l as any)._originalStyle);
      }
      // 兼容 L.GeoJSON 类型（FeatureGroup 或 LayerGroup）
      if ((l as any).eachLayer) {
        (l as any).eachLayer((subLayer: any) => {
          if (subLayer && subLayer.setStyle && subLayer._originalStyle) {
            subLayer.setStyle(subLayer._originalStyle);
          }
        });
      }
    });
    // ——保证和框选一致，_lastSelected 只包含当前选中的——
    this._lastSelected = [];
    let selected = null;
    // 判断是否真的选中了要素（layer）
    if (layer && this.layers.includes(layer)) {
      selected = layer;
      this._lastSelected = [layer];
      if (!(layer as any)._originalStyle && (layer as any).options) {
        (layer as any)._originalStyle = { ...(layer as any).options };
      }
      (layer as any).setStyle?.({
        color: '#2196f3',
        weight: 3,
        fillColor: '#2196f3',
        fillOpacity: 0.7
      });
      // 兼容 L.GeoJSON 类型
      if ((layer as any).eachLayer) {
        (layer as any).eachLayer((subLayer: any) => {
          if (!(subLayer as any)._originalStyle && (subLayer as any).options) {
            (subLayer as any)._originalStyle = { ...(subLayer as any).options };
          }
          if (subLayer && subLayer.setStyle) {
            subLayer.setStyle({
              color: '#2196f3',
              weight: 3,
              fillColor: '#2196f3',
              fillOpacity: 0.7
            });
          }
        });
      }
      this.selectedLayer = layer;
      this.originalStyle = { ...(layer as any).options || {} };
    } else {
      // 没有选中任何要素，selectedLayer等全部清空
      this.selectedLayer = null;
      this.originalStyle = null;
    }
    if (onSelect && selected) onSelect(selected as L.Layer);
  };

  private handleMouseOver = (e: any) => {
    const layer = e.target as L.Layer;
    (layer as any).setStyle?.({ weight: 6 });
  };

  private handleMouseOut = (e: any) => {
    const layer = e.target as L.Layer;
    if (this.selectedLayer !== layer) {
      (layer as any).setStyle?.({ weight: 3 });
    }
  };

  // 矩形选择
  private enableRectangleSelect(onSelect?: (layers: L.Layer[]) => void) {
    let rect: L.Rectangle | null = null;
    let startPoint: L.LatLng | null = null;
    let endPoint: L.LatLng | null = null;
    let isDrawing = false;
    const onMapMouseDown = (e: L.LeafletMouseEvent) => {
      if (isDrawing) return;
      isDrawing = true;
      startPoint = e.latlng;
      rect = L.rectangle([
        [startPoint.lat, startPoint.lng],
        [startPoint.lat, startPoint.lng]
      ] as [L.LatLngTuple, L.LatLngTuple], { color: '#2196f3', weight: 2, dashArray: '4', fillColor: '#2196f3', fillOpacity: 0.2, interactive: false }).addTo(this.map);
      this._tempRect = rect;
      this.map.on('mousemove', onMouseMove);
      this.map.getContainer().addEventListener('contextmenu', onDomContextMenu);
    };
    const onMouseMove = (e: L.LeafletMouseEvent) => {
      if (rect && startPoint) {
        endPoint = e.latlng;
        rect.setBounds(L.latLngBounds([
          [startPoint.lat, startPoint.lng],
          [endPoint.lat, endPoint.lng]
        ] as [L.LatLngTuple, L.LatLngTuple]));
      }
    };
    const onDomContextMenu = (e: MouseEvent) => {
      if (!isDrawing || !rect || !startPoint || !endPoint) return;
      e.preventDefault();
      if (!(e.target instanceof HTMLElement) || !this.map.getContainer().contains(e.target)) return;
      const bounds = rect.getBounds();
      // 判断是否按下 shift
      const mouseEvent = e as MouseEvent;
      const isShift = mouseEvent.shiftKey;
      // shift 未按下时，重置所有高亮
      if (!isShift) {
        this.layers.forEach(layer => {
          if ((layer as any)._originalStyle) {
            (layer as any).setStyle?.((layer as any)._originalStyle);
          }
        });
        this._lastSelected = [];
      }
      // 选中并高亮图层（蓝色高亮）
      const selected = this.layers.filter(layer => {
        if ((layer as any).getLatLng) {
          return bounds.contains((layer as any).getLatLng());
        } else if ((layer as any).getLatLngs) {
          const latlngs = (layer as any).getLatLngs().flat(2);
          return latlngs.some((pt: L.LatLng) => bounds.contains(pt));
        }
        return false;
      });
      selected.forEach(l => {
        if (!(l as any)._originalStyle && (l as any).options) {
          (l as any)._originalStyle = { ...(l as any).options };
        }
        (l as any).setStyle?.({ color: '#2196f3', weight: 3, fillColor: '#2196f3', fillOpacity: 0.7 });
      });
      // shift 多选时，合并高亮
      if (isShift) {
        this._lastSelected = Array.from(new Set([...this._lastSelected, ...selected]));
      } else {
        this._lastSelected = selected;
      }
      if (onSelect) onSelect(this._lastSelected);
      // 立即移除矩形
      this.map.removeLayer(rect);
      this._tempRect = null;
      this.map.off('mousemove', onMouseMove);
      this.map.getContainer().removeEventListener('contextmenu', onDomContextMenu);
      isDrawing = false;
      this.map.once('mousedown', onMapMouseDown);
    };
    this._onDomContextMenu = onDomContextMenu;
    this._rectangleMouseDownHandler = onMapMouseDown;
    this._rectangleMouseMoveHandler = onMouseMove;
    this._rectangleContextMenuHandler = onDomContextMenu;
    this.map.once('mousedown', onMapMouseDown);
  }

  // 多边形选择（集成 DrawInteraction 绘制多边形，选中范围内要素）
  private enablePolygonSelect(onSelect?: (layers: L.Layer[]) => void) {
    // 兼容 SSR/非 window 场景
    const DrawInteraction = (window as any).DrawInteraction || undefined;
    if (!DrawInteraction) {
      console.error('DrawInteraction 未挂载到 window，无法使用多边形选中');
      return;
    }
    const draw = new DrawInteraction(this.map);
    draw.startDrawMode('polygon', (polygonPoints: L.LatLng[], event?: MouseEvent) => {
      const polygon = L.polygon(polygonPoints, { color: '#ff9800', fillColor: '#ffe082', dashArray: '4 4', weight: 2 }).addTo(this.map);
      // 判断是否按下 shift
      const isShift = !!event?.shiftKey;
      // shift 未按下时，重置所有高亮
      if (!isShift) {
        this.layers.forEach(layer => {
          if ((layer as any)._originalStyle) {
            (layer as any).setStyle?.((layer as any)._originalStyle);
          }
        });
        this._lastSelected = [];
      }
      const selected = this.layers.filter(layer => {
        if ((layer as any).getLatLng) {
          return this.pointInPolygon((layer as any).getLatLng(), polygonPoints);
        } else if ((layer as any).getLatLngs) {
          const latlngs = (layer as any).getLatLngs().flat(2);
          return latlngs.some((pt: L.LatLng) => this.pointInPolygon(pt, polygonPoints));
        }
        return false;
      });
      selected.forEach(l => {
        if (!(l as any)._originalStyle && (l as any).options) {
          (l as any)._originalStyle = { ...(l as any).options };
        }
        (l as any).setStyle?.({ color: '#2196f3', weight: 3, fillColor: '#2196f3', fillOpacity: 0.7 });
      });
      // shift 多选时，合并高亮
      if (isShift) {
        this._lastSelected = Array.from(new Set([...this._lastSelected, ...selected]));
      } else {
        this._lastSelected = selected;
      }
      if (onSelect) onSelect(this._lastSelected);
      this.map.removeLayer(polygon);
    });
  }

  // 点是否在多边形内（射线法）
  private pointInPolygon(point: L.LatLng, vs: L.LatLng[]): boolean {
    const x = point.lng, y = point.lat;
    let inside = false;
    for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) {
      const xi = vs[i].lng, yi = vs[i].lat;
      const xj = vs[j].lng, yj = vs[j].lat;
      const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi + 1e-10) + xi);
      if (intersect) inside = !inside;
    }
    return inside;
  }
}
